package cn.htsyb.synergy.utils;

import jakarta.validation.constraints.NotNull;

import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
 * 
 * @author lakeside hubin_yuan.410@hotmail.com
 * @version V1.0.0
 * @since 1.0
 * @date 2022/5/11
 */
public class CompressUtil {

    /**
     * 解压缩
     *
     * @param zipFileName
     * @param fileDir
     * @throws IOException
     */
    public static void zipDecompression(String zipFileName, String fileDir) throws IOException {
        try (FileInputStream fileInStream = new FileInputStream(new File(zipFileName));
             ZipInputStream zipInStream = new ZipInputStream(fileInStream);
             ReadableByteChannel readableByteChannel = Channels.newChannel(zipInStream)) {
            ZipEntry zipEntry = null;
            while ((zipEntry = zipInStream.getNextEntry()) != null) {
                File file = new File(fileDir + zipEntry.getName());
                FileUtil.mkdirsPath(file.getParentFile());
                IOUtil.nioTransferStreamToFile(readableByteChannel, file);
            }
        }
    }

    /**
     * 压缩文件列表到某个zip
     *
     * @param zipFileName
     * @param fileNames
     * @throws IOException
     */
    public static void zipCompress(String zipFileName, String... fileNames) throws IOException {
        try (FileOutputStream fileOutStream = new FileOutputStream(zipFileName)) {
            zipCompress(fileOutStream, fileNames);
        }
    }

    public static void zipCompress(@NotNull OutputStream outStream, Collection<String> fileNameList) throws IOException {
        try (ZipOutputStream zipOutStream = new ZipOutputStream(outStream);
             WritableByteChannel writeByteChannel = Channels.newChannel(zipOutStream)) {
            for (String fileName : fileNameList) {
                if (fileName != null && fileName.length() > 0) {
                    File file = new File(fileName);
                    if (file.exists()) {
                        zipNioCompress(zipOutStream, writeByteChannel, "/", file);
                    }
                }
            }
        }
    }

    public static void zipCompress(@NotNull OutputStream outStream, String... fileNames) throws IOException {
        zipCompress(outStream, Arrays.asList(fileNames));
    }

    private static void zipNioCompress(@NotNull ZipOutputStream zipOutStream, @NotNull WritableByteChannel writeByteChannel, String basePath, @NotNull File file) throws IOException {
        String entryName = basePath + file.getName();
        if (file.isDirectory()) {
            for (File subFile : file.listFiles()) {
                zipNioCompress(zipOutStream, writeByteChannel, entryName + "/", subFile);
            }
        } else {
            zipOutStream.putNextEntry(new ZipEntry(entryName));
            IOUtil.nioTransferFileToStream(writeByteChannel, FileChannel.open(file.toPath(), EnumSet.of(StandardOpenOption.READ)));
        }
    }

    private static void zipCompress(@NotNull ZipOutputStream zipOutStream, @NotNull String basePath, @NotNull String fileName) throws IOException {
        if (fileName != null && fileName.length() > 0) {
            File file = new File(fileName);
            if (file.exists()) {
                String entryName = basePath + file.getName();
                if (file.isDirectory()) {
                    for (File subFile : file.listFiles()) {
                        zipCompress(zipOutStream, entryName + "/", subFile.getPath());
                    }
                } else {
                    zipOutStream.putNextEntry(new ZipEntry(entryName));
                    try (FileInputStream fileInStream = new FileInputStream(file)) {
                        IOUtil.transferStream(fileInStream, zipOutStream);
                    }
                }
            }
        }
    }

    public static void main(String[] agrs) {
        String fileName = "E:\\Compress\\";
        try {
            CompressUtil.zipCompress("E:\\Compress.zip", fileName);
            CompressUtil.zipDecompression("E:\\Compress.zip", "E:\\compression\\");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
